//
//  main.m
//  OC08_Category_Extension_Protocol
//
//  Created by Scott on 16/3/5.
//  Copyright © 2016年 Scott. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
#import "NSArray+GetSecondItem.h"
#import "NSString+GetFirstLetterCapital.h"
#import "Woman.h"
#import "Girl.h"
#import "Boy.h"
/** 知识点:Protocol */
void chapterOfprotocol(){
    /**
     * 协议:一堆方法的声明,只有.h文件,没有.m文件.
     * 可以被任何类签订.
     * 谁签订协议谁负责实现协议中声明的方法.
     * 协议中的方法同样可以被子类继承.
     */
    
    Person *per = [[Person alloc] init];
    [per say];
    [per sayToPerson:@"tony"];
    
    /** 未被实现的方法不能被调用,否则程序会Crash. */
//    [per sayBy];
    
    
}

/** 知识点: category */
void chapterOfCategory() {
    
    /**
     * Category 类目
        向已有的类添加方法,从而达到扩展已有类的目的.在某些情况下Category比创建子类更优.类目的方法同样也是可以被继承的.
     
     * 优点:
        可以向没有源码的类添加方法.
     */
    
    NSArray *array = @[@"345",@"haoxin",@"lizhi"];
    NSString *str = [array getSecondObject];
    
    NSLog(@"array的第二个元素是: %@",str);
    
    NSMutableArray *mArray = @[@"345"].mutableCopy;
    NSString *str2 = [mArray getSecondObject];
    NSLog(@"%@",str2);
    
    //练习:为NSString类扩展一个新的方法,要求获取字符串的首字母大写.
    
    NSString *a = @"abcdef";
    NSLog(@"%@",[a getCapital]);
    
    //类目可以添加属性和实例变量.详见NSString+GetFirstLetterCapital的.h和.m文件
    NSLog(@"%ld",[a midIndex]);
    /**
     * 类目可以添加和原来类里相同方法名的方法.类目里的方法会覆盖掉原来的方法,调用时只会调用类目里的方法.
     * 类目同样可以向有源码的类添加方法,多用于分类管理功能.详见Person.h和Person.m文件
     *
     */
    Person *person = [[Person alloc] initWithName:@"lijie"];
    NSLog(@"name :%@",person.name);
    
}

/** 知识点: extension. */
void chapterOfExtension() {
    
    /**
     * 延展的作用就是封装,可以把没有必要给用户看的细节隐藏起来,对外的.h是希望给用户使用的属性和方法.
     * 优点:可以添加私有属性和私有方法.
     * 缺点:延展必须要有源码的情况下才可以使用.
     */
    Woman *woman = [[Woman alloc] initWithName:@"chengcheng" withAge:25 ];
    
    //私有属性外部无法访问.
   // woman.weight
    //私有方法外部无法调用.
   // [woman info];
    
    
}

/** 知识点: protocol, delegate. */
void chapterOfProtocelDelegate() {
    
    /**
     * delegate 设计模式 
     * 协议的核心使用场景就是delegate设计模式
     
     * delegate (代理) 相当于代理商,帮你完成一些任务.
     
     * 只需要通知代理去做某事.
     */
    
    /**
     * delegate设计模式步骤
     
     1. 声明协议
     2. 设置代理人属性.
     3. 让代理人调用方法.
     4. 签订协议
     5. 指定代理人
     6. 实现协议方法  //声明之后就可以实现.并不一定要在最后
     
     */
    
    Girl *girl = [[Girl alloc] init];
    girl.name = @"Susan";
    girl.age = 25;
    
    Boy *boy1 = [[Boy alloc] init];
    boy1.name = @"Tom";
    boy1.age = 25;
    
    Boy *boy2 = [[Boy alloc] init];
    boy2.name = @"zhangsan";
    boy2.age = 26;
    
    
#warning 5.指定代理人
    //代理人可以更换,girl可以更换不同的代理人.
    girl.delgate = boy1;
    
    [girl getMarry]; 
}


#pragma mark - MAIN FUNCTION
int main(int argc, const char * argv[]) {

    chapterOfprotocol();
    
    
#pragma mark - 知识点1: Category (类目)
    chapterOfCategory();
    
#pragma mark - 知识点2: Extension (延展)
    chapterOfExtension();
    
#pragma mark - 知识点3: Protocol , delegate
    chapterOfProtocelDelegate();
    
    
    return 0;
}
